use std::str::FromStr;

use chrono::Local;
use sea_orm::{
    ActiveModelTrait, ColumnTrait, EntityTrait, Iterable, NotSet, PaginatorTrait, QueryOrder,
    QuerySelect,
};
use sea_orm::ActiveValue::Set;
use sea_orm::QueryFilter;

use common::ctx::get_db;
use common::error::MyError;
use common::page::{BasePage, PageResult};
use entity::prelude::User;
use entity::user;
use model::auth::RegisterModel;
use model::user::{CreateUser, UserPage};
use security::bcrypt::hash_context;

use crate::manager::base::BaseManager;
use crate::manager::role::RoleManager;

pub struct UserManager {}

impl BaseManager<i64, user::Model, UserPage, CreateUser, user::Model> for UserManager {
    async fn list() -> Result<Vec<user::Model>, MyError> {
        let res = User::find()
            .select_only()
            .columns(user::Column::iter().filter(|col| match col {
                user::Column::Id => true,
                user::Column::UserName => true,
                user::Column::NickName => true,
                _ => false,
            }))
            .all(&*get_db()?)
            .await?;
        Ok(res)
    }

    async fn page(user_page: UserPage) -> Result<PageResult<user::Model>, MyError> {
        let mut page_data = user_page.get_page_data();
        //校验分页数据是否合法
        page_data = page_data.check();

        let mut find = User::find();

        find = find
            .select_only()
            .columns(user::Column::iter().filter(|col| match col {
                user::Column::Password => false,
                _ => true,
            }));

        if let Some(id) = user_page.id {
            find = find.filter(user::Column::Id.eq(id))
        }

        if let Some(user_name) = user_page.user_name {
            find = find.filter(user::Column::UserName.like(format!("%{}%", user_name)))
        }

        if let Some(nick_name) = user_page.nick_name {
            find = find.filter(user::Column::NickName.like(format!("%{}%", nick_name)))
        }

        if let Some(status) = user_page.status {
            find = find.filter(user::Column::Status.eq(status))
        }

        if let Some(create_time) = user_page.create_time {
            find = find.filter(
                user::Column::CreateTime.between(create_time[0].clone(), create_time[1].clone()),
            )
        }

        if let Some(last_login_time) = user_page.last_login_time {
            find = find.filter(
                user::Column::LastLoginTime
                    .between(last_login_time[0].clone(), last_login_time[1].clone()),
            )
        }

        if let Some(sorter) = page_data.sorter {
            let field = user::Column::from_str(sorter.field.as_str()).or_else(|e| {
                Err(MyError::DBError(format!(
                    "获取排序字段失败：{}",
                    e.to_string()
                )))
            })?;
            find = find.order_by(field, sorter.order());
        }
        let db_conn = &*get_db()?;
        let paginator = find.paginate(db_conn, page_data.page_size);

        //分页查询
        let record = paginator.fetch_page(page_data.page - 1).await?;
        //总条数
        let total = paginator.num_items().await?;
        //返回分页结果
        Ok(PageResult {
            page: page_data.page,
            page_size: page_data.page_size,
            total,
            record,
        })
    }

    async fn info(user_id: i64) -> Result<Option<user::Model>, MyError> {
        let res = User::find_by_id(user_id).one(&*get_db()?).await?;
        Ok(res)
    }

    async fn add(form: CreateUser) -> Result<i64, MyError> {
        let user_name = form
            .user_name
            .ok_or(MyError::ServerError("用户名不能为空".to_string()))?;
        UserManager::check_user_name_exist(user_name.clone()).await?;
        let nick_name = form
            .nick_name
            .ok_or(MyError::ServerError("昵称不能为空".to_string()))?;
        UserManager::check_user_nick_name_exist(nick_name.clone()).await?;
        let email = form
            .email
            .ok_or(MyError::ServerError("邮箱不能为空".to_string()))?;
        UserManager::check_user_email_exist(email.clone()).await?;
        let password = form
            .password
            .ok_or(MyError::ServerError("密码不能为空".to_string()))?;
        let password = hash_context(password)?;
        let model = user::ActiveModel {
            id: NotSet,
            user_name: Set(Some(user_name)),
            password: Set(Some(password)),
            nick_name: Set(Some(nick_name)),
            email: Set(Some(email)),
            email_status: Set(Some(false)),
            status: Set(Some(true)),
            create_time: Set(Option::from(Local::now().naive_local())),
            update_time: NotSet,
            ..Default::default()
        }
        .insert(&*get_db()?)
        .await?;
        RoleManager::set_user_role(model.id, vec![2]).await?;
        Ok(model.id)
    }

    async fn update(form: user::Model) -> Result<i64, MyError> {
        let entity =
            User::find_by_id(form.id)
                .one(&*get_db()?)
                .await?
                .ok_or(MyError::ServerError(format!(
                    "user [{:?}] does not exist",
                    form.id
                )))?;
        let mut entity: user::ActiveModel = entity.into();
        if let Some(nick_name) = form.nick_name {
            entity.nick_name = Set(Option::from(
                UserManager::check_user_nick_name_and_id_not_in(nick_name, form.id.clone()).await?,
            ));
        }
        if form.status.is_some() {
            entity.status = Set(form.status);
        }
        if form.email_status.is_some() {
            entity.email_status = Set(form.email_status);
        }
        if let Some(user_name) = form.user_name {
            entity.user_name = Set(Option::from(
                UserManager::check_user_name_exist_and_id_not_in(
                    user_name.clone(),
                    form.id.clone(),
                )
                .await?,
            ));
        }
        if let Some(email) = form.email {
            entity.email = Set(Option::from(
                UserManager::check_user_email_exist_and_id_not_in(email.clone(), form.id.clone())
                    .await?,
            ));
        }
        entity.update_time = Set(Some(Local::now().naive_local()));
        let result = entity.update(&*get_db()?).await?;
        Ok(result.id)
    }

    async fn delete(user_id: i64) -> Result<bool, MyError> {
        let res = User::delete_by_id(user_id).exec(&*get_db()?).await?;
        Ok(res.rows_affected == 1)
    }
}

impl UserManager {
    pub async fn register_user_data(form: RegisterModel) -> Result<bool, MyError> {
        let user_name = form
            .user_name
            .ok_or(MyError::ServerError("用户名不能为空".to_string()))?;
        UserManager::check_user_name_exist(user_name.clone()).await?;
        let email = form
            .email
            .ok_or(MyError::ServerError("邮箱不能为空".to_string()))?;
        UserManager::check_user_email_exist(email.clone()).await?;
        let nick_name = form
            .nick_name
            .ok_or(MyError::ServerError("昵称不能为空".to_string()))?;
        UserManager::check_user_nick_name_exist(nick_name.clone()).await?;
        let password = form
            .password
            .ok_or(MyError::ServerError("密码不能为空".to_string()))?;
        let password = hash_context(password)?;
        let model = user::ActiveModel {
            id: NotSet,
            user_name: Set(Some(user_name)),
            password: Set(Some(password)),
            nick_name: Set(Some(nick_name)),
            email: Set(Some(email)),
            email_status: Set(Some(false)),
            status: Set(Some(true)),
            create_time: Set(Some(Local::now().naive_local())),
            update_time: NotSet,
            last_login_time: NotSet,
        }
        .insert(&*get_db()?)
        .await;
        let res = model.is_ok();
        if res {
            RoleManager::set_user_role(model.unwrap().id, vec![2]).await?;
        }
        Ok(res)
    }
    pub async fn exist_by_name(user_name: String) -> Result<bool, MyError> {
        let exist = User::find()
            .filter(user::Column::UserName.eq(user_name))
            .all(&*get_db()?)
            .await?
            .len()
            > 0;
        Ok(exist)
    }

    pub async fn exist_by_email(email: String) -> Result<bool, MyError> {
        let exist = User::find()
            .filter(user::Column::Email.eq(email))
            .all(&*get_db()?)
            .await?
            .len()
            > 0;
        Ok(exist)
    }

    pub async fn exist_by_nick_name(nick_name: String) -> Result<bool, MyError> {
        let exist = User::find()
            .filter(user::Column::NickName.eq(nick_name))
            .all(&*get_db()?)
            .await?
            .len()
            > 0;
        Ok(exist)
    }

    pub async fn exist_by_name_and_id_not_in(user_name: String, uid: i64) -> Result<bool, MyError> {
        Ok(User::find()
            .filter(user::Column::UserName.eq(user_name))
            .filter(user::Column::Id.ne(uid))
            .all(&*get_db()?)
            .await?
            .len()
            > 0)
    }

    pub async fn exist_by_email_and_id_not_in(email: String, uid: i64) -> Result<bool, MyError> {
        Ok(User::find()
            .filter(user::Column::Email.eq(email))
            .filter(user::Column::Id.ne(uid))
            .all(&*get_db()?)
            .await?
            .len()
            > 0)
    }

    pub async fn exist_by_nick_name_and_id_not_in(
        nick_name: String,
        uid: i64,
    ) -> Result<bool, MyError> {
        Ok(User::find()
            .filter(user::Column::NickName.eq(nick_name))
            .filter(user::Column::Id.ne(uid))
            .all(&*get_db()?)
            .await?
            .len()
            > 0)
    }

    pub async fn check_user_name_exist(user_name: String) -> Result<String, MyError> {
        if UserManager::exist_by_name(user_name.clone()).await? {
            Err(MyError::ServerError(format!("用户名[{}]已存在", user_name)))
        } else {
            Ok(user_name)
        }
    }

    pub async fn check_user_email_exist(email: String) -> Result<String, MyError> {
        if UserManager::exist_by_email(email.clone()).await? {
            Err(MyError::ServerError(format!("邮箱[{}]已存在", email)))
        } else {
            Ok(email)
        }
    }

    pub async fn check_user_nick_name_exist(nick_name: String) -> Result<String, MyError> {
        if UserManager::exist_by_nick_name(nick_name.clone()).await? {
            Err(MyError::ServerError(format!("昵称[{}]已存在", nick_name)))
        } else {
            Ok(nick_name)
        }
    }

    pub async fn check_user_name_exist_and_id_not_in(
        user_name: String,
        uid: i64,
    ) -> Result<String, MyError> {
        if UserManager::exist_by_name_and_id_not_in(user_name.clone(), uid).await? {
            Err(MyError::ServerError(format!("用户名[{}]已存在", user_name)))
        } else {
            Ok(user_name.clone())
        }
    }

    pub async fn check_user_email_exist_and_id_not_in(
        email: String,
        uid: i64,
    ) -> Result<String, MyError> {
        if UserManager::exist_by_email_and_id_not_in(email.clone(), uid).await? {
            Err(MyError::ServerError(format!("邮箱[{}]已存在", email)))
        } else {
            Ok(email.clone())
        }
    }
    pub async fn check_user_nick_name_and_id_not_in(
        nick_name: String,
        uid: i64,
    ) -> Result<String, MyError> {
        if UserManager::exist_by_nick_name_and_id_not_in(nick_name.clone(), uid).await? {
            Err(MyError::ServerError(format!("昵称[{}]已存在", nick_name)))
        } else {
            Ok(nick_name.clone())
        }
    }

    pub async fn get_user_by_user_name(user_name: String) -> Result<Option<user::Model>, MyError> {
        let user = User::find()
            .filter(user::Column::UserName.eq(user_name))
            .one(&*get_db()?)
            .await?;
        Ok(user)
    }

    pub async fn reset_password(uid: i64, password: String) -> Result<bool, MyError> {
        user::ActiveModel {
            id: Set(uid),
            user_name: NotSet,
            password: Set(Some(password)),
            nick_name: NotSet,
            email: NotSet,
            email_status: NotSet,
            status: NotSet,
            create_time: Set(Some(Local::now().naive_local())),
            update_time: NotSet,
            last_login_time: NotSet,
        }
        .update(&*get_db()?)
        .await?;
        Ok(true)
    }

    pub async fn update_login_time(uid: i64) -> Result<bool, MyError> {
        let entity = User::find_by_id(uid)
            .one(&*get_db()?)
            .await?
            .ok_or(MyError::ServerError(format!(
                "user [{:?}] does not exist",
                uid
            )))?;
        let mut entity: user::ActiveModel = entity.into();
        entity.last_login_time = Set(Some(Local::now().naive_local()));
        entity.update(&*get_db()?).await?;
        Ok(true)
    }

    pub async fn get_user_by_email(email: &String) -> Result<Option<user::Model>, MyError> {
        let user = User::find()
            .filter(user::Column::Email.eq(email))
            .one(&*get_db()?)
            .await?;
        Ok(user)
    }
}
